from typing import List

from pyecharts import charts

import pyecharts.options as opts
from pyecharts.commons.utils import JsCode

from emi.bar.data import BarData, Interval
from emi.util import utils
# try:
#     from emi_selenium.GF_Account_main import GFOrder
# except Exception:
#     pass
from . import _utils
from ._utils import make_k_bars_data


def build_kline_chart(bars:List, pre_close = None):
    """
    构建K线图
    """
    is_daily = bars[0].interval >= Interval.DAILY
    data_map = make_k_bars_data(bars,is_daily)
    time_list = data_map['time']
    candle_values = data_map['k_bar']
    volume_list = data_map['volume']

    close_values_list = [kbar[1] for kbar in candle_values]
    # for vol in volume_list:
    #     assert vol >= 0
    mark_lines = []
    min_ = "dataMin"
    max_ = "dataMax"
    if pre_close is not None:
        # min_ = pre_close*1.1
        # max_ = pre_close * 0.89
        mark_lines.append(opts.MarkLineItem(name=f"0%", y=pre_close,symbol="none") )
        for v in [1.015,1.025,1.035,1.045,1.055,]:
            mark_lines.append(opts.MarkLineItem(name=f"{(v -1) * 100}%", y=pre_close * v ),)
        for v in [0.985,0.975,0.965,0.955,0.945,]:
            mark_lines.append(opts.MarkLineItem(name=f"{(v -1) * 100}%", y=pre_close * v, ),)


    kline = (
        charts.Line()
            .add_xaxis(xaxis_data=time_list)
            .add_yaxis(
            series_name="Dow-Jones index",
            y_axis=close_values_list,
            label_opts=opts.LabelOpts(is_show=False),

            ##itemstyle_opts=opts.ItemStyleOpts(color="#ec0000", color0="#00da3c"),
            )
            .set_global_opts(
            legend_opts=opts.LegendOpts(
                is_show=False, pos_bottom=10, pos_left="center"
            ),
            yaxis_opts=opts.AxisOpts(
                is_scale=True,
                splitarea_opts=opts.SplitAreaOpts(
                    is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1)
                ),
                min_=min_,
                max_=max_,
            ),
            tooltip_opts=opts.TooltipOpts(
                trigger="axis",
                axis_pointer_type="cross",
                background_color="rgba(245, 245, 245, 0.8)",
                border_width=1,
                border_color="#ccc",
                textstyle_opts=opts.TextStyleOpts(color="#000"),
            ),
            )
            .set_series_opts(
            markline_opts=opts.MarkLineOpts(
                    data=mark_lines,
                    is_silent=False,
                    label_opts = opts.LabelOpts(is_show=True)
            )
        )
    )


    bar = (
        charts.Bar()
            .add_xaxis(xaxis_data=candle_values)
            .add_yaxis(
            series_name="Volume",
            y_axis=volume_list,
            xaxis_index=1,
            yaxis_index=1,
            label_opts=opts.LabelOpts(is_show=False),
        )
            .set_global_opts(
            xaxis_opts=opts.AxisOpts(
                type_="category",
                is_scale=True,
                grid_index=1,
                boundary_gap=False,
                axisline_opts=opts.AxisLineOpts(is_on_zero=False),
                axistick_opts=opts.AxisTickOpts(is_show=False),
                splitline_opts=opts.SplitLineOpts(is_show=False),
                axislabel_opts=opts.LabelOpts(is_show=False),
                split_number=20,
                min_="dataMin",
                max_="dataMax",
            ),
            yaxis_opts=opts.AxisOpts(
                grid_index=1,
                is_scale=True,
                split_number=2,
                axislabel_opts=opts.LabelOpts(is_show=False),
                axisline_opts=opts.AxisLineOpts(is_show=False),
                axistick_opts=opts.AxisTickOpts(is_show=False),
                splitline_opts=opts.SplitLineOpts(is_show=False),
            ),
            legend_opts=opts.LegendOpts(is_show=False),
        )
    )

    # Kline And Line
    # overlap_kline_line = kline

    # Grid Overlap + Bar
    grid_chart = charts.Grid(
        init_opts=opts.InitOpts(
            width="100%",
            height="600px",
            animation_opts=opts.AnimationOpts(animation=False),
        )
    )
    grid_chart.add(
        kline,
        grid_opts=opts.GridOpts(pos_left="10%", pos_right="8%", height="50%"),
    )
    grid_chart.add(
        bar,
        grid_opts=opts.GridOpts(
            pos_left="10%", pos_right="8%", pos_top="63%", height="16%"
        ),
    )

    return grid_chart

def build_kbar_chart(bars:List,title = "",is_daily:bool = None):
    """
    构建K线图
    """
    if is_daily is None:
        is_daily = bars[0].interval >= Interval.DAILY
    data_map = _utils.make_k_bars_data(bars, is_daily)
    time_list = data_map['time']
    candle_values = data_map['k_bar']
    volume_list = data_map['volume']

    MAX_SHOW_BAR_SIZE = 50
    if not is_daily:
        ## 分钟、分时频率
        MAX_SHOW_BAR_SIZE = 250
        tool_tip_fun = JsCode("""
                            function(params) {
                                try{
                                    var prices = params[0].data;
                                    var open = prices[1];
                                    var close = prices[2];
                                    var low = prices[3];
                                    var high = prices[4];
                                    var pre_close = prices[5];
                                    var pnl =  100 * (close - pre_close) / pre_close;
                                    var pnl2 =  100 * (close - open) / open;
                                    return  '总pnl:  '+pnl.toFixed(2)+'%<br/>'+
                                            '单位pnl:'+pnl2.toFixed(2)+'%<br/>'+
                                            'close:  ' + close.toFixed(2) + '<br/>'+
                                            'open:   ' + open.toFixed(2) + '<br/>'+
                                            'low     ' + low.toFixed(2) + '<br/>'+
                                            'high:   ' + high.toFixed(2);
                                }catch(error){
                                    return ''
                                }
    
                            }
                        """)
    else:
        tool_tip_fun = JsCode("""
                                function(params) {
                                  try{
                                      var prices = params[0].data;
                                      var open = prices[1];
                                      var close = prices[2];
                                      var low = prices[3];
                                      var high = prices[4];
                                      var pre_close = prices[5];
                                      var pnl =  100 * (close - pre_close) / pre_close;
                                      return  'pnl:  '+pnl.toFixed(2)+'%<br/>'+
                                              'close:  ' + close.toFixed(2) + '<br/>'+
                                              'open:   ' + open.toFixed(2) + '<br/>'+
                                              'low     ' + low.toFixed(2) + '<br/>'+
                                              'high:   ' + high.toFixed(2);
                                  }catch(error){
                                    return ''
                                 }

                              }
                          """)

    if len(candle_values) > MAX_SHOW_BAR_SIZE:
        _range_start = int( 100 *(1 - MAX_SHOW_BAR_SIZE /len(candle_values)))
    else:
        _range_start = 0

    kline = (
        charts.Kline()
            .add_xaxis(xaxis_data=time_list)
            .add_yaxis(
            series_name="k柱",
            y_axis=candle_values,
            itemstyle_opts=opts.ItemStyleOpts(color="#ec0000", color0="#00da3c"),
        )
            .set_global_opts(
            title_opts=opts.TitleOpts(title=title, pos_top="90%"),
            legend_opts=opts.LegendOpts(
                is_show=False, pos_bottom=10, pos_left="center"
            ),
            datazoom_opts=[
                opts.DataZoomOpts(
                    is_show=False,
                    type_="inside",
                    xaxis_index=[0, 1],
                    range_start=_range_start,
                    range_end=100,
                ),
                opts.DataZoomOpts(
                    is_show=True,
                    xaxis_index=[0, 1],
                    type_="slider",
                    pos_top="85%",
                    range_start=_range_start,
                    range_end=100,
                ),
            ],
            yaxis_opts=opts.AxisOpts(
                is_scale=True,
                splitarea_opts=opts.SplitAreaOpts(
                    is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1)
                ),
            ),
            tooltip_opts=opts.TooltipOpts(
                trigger="axis",
                axis_pointer_type="cross",
                background_color="rgba(245, 245, 245, 0.8)",
                border_width=1,
                border_color="#ccc",
                formatter= tool_tip_fun,
                textstyle_opts=opts.TextStyleOpts(color="#000"),
            ),
            axispointer_opts=opts.AxisPointerOpts(
                is_show=True,
                link=[{"xAxisIndex": "all"}],
                label=opts.LabelOpts(background_color="#777"),
            ),
            brush_opts=opts.BrushOpts(
                x_axis_index="all",
                brush_link="all",
                out_of_brush={"colorAlpha": 0.1},
                brush_type="lineX",
            ),
        )


    )

    line = (
        charts.Line()
            .add_xaxis(xaxis_data=time_list)
            .add_yaxis(
            series_name="MA5",
            y_axis=_utils.calculate_ma(day_count=5, values=candle_values),
            is_smooth=True,
            is_hover_animation=False,
            linestyle_opts=opts.LineStyleOpts(width=1, opacity=0.5),
            label_opts=opts.LabelOpts(is_show=False),
        )
            .add_yaxis(
            series_name="MA10",
            y_axis=_utils.calculate_ma(day_count=10, values=candle_values),
            is_smooth=True,
            is_hover_animation=False,
            linestyle_opts=opts.LineStyleOpts(width=1, opacity=0.5),
            label_opts=opts.LabelOpts(is_show=False),
        )
            .add_yaxis(
            series_name="MA20",
            y_axis=_utils.calculate_ma(day_count=20, values=candle_values),
            is_smooth=True,
            is_hover_animation=False,
            linestyle_opts=opts.LineStyleOpts(width=1, opacity=0.5),
            label_opts=opts.LabelOpts(is_show=False),
        )
            .add_yaxis(
            series_name="MA30",
            y_axis=_utils.calculate_ma(day_count=30, values=candle_values),
            is_smooth=True,
            is_hover_animation=False,
            linestyle_opts=opts.LineStyleOpts(width=1, opacity=0.5),
            label_opts=opts.LabelOpts(is_show=False),
        )
            .set_global_opts(xaxis_opts=opts.AxisOpts(type_="category"))
    )

    bar = (
        charts.Bar()
            .add_xaxis(xaxis_data=candle_values)
            .add_yaxis(
            series_name="Volume",
            y_axis=volume_list,
            xaxis_index=1,
            yaxis_index=1,
            label_opts=opts.LabelOpts(is_show=False),
        )
            .set_global_opts(
            xaxis_opts=opts.AxisOpts(
                type_="category",
                is_scale=True,
                grid_index=1,
                boundary_gap=False,
                axisline_opts=opts.AxisLineOpts(is_on_zero=False),
                axistick_opts=opts.AxisTickOpts(is_show=False),
                splitline_opts=opts.SplitLineOpts(is_show=False),
                axislabel_opts=opts.LabelOpts(is_show=False),
                split_number=20,
                min_="dataMin",
                max_="dataMax",
            ),
            yaxis_opts=opts.AxisOpts(
                grid_index=1,
                is_scale=True,
                split_number=2,
                axislabel_opts=opts.LabelOpts(is_show=False),
                axisline_opts=opts.AxisLineOpts(is_show=False),
                axistick_opts=opts.AxisTickOpts(is_show=False),
                splitline_opts=opts.SplitLineOpts(is_show=False),
            ),
            legend_opts=opts.LegendOpts(is_show=False),
        )
    )

    # Kline And Line
    overlap_kline_line = kline.overlap(line)

    # overlap_kline_line = kline

    # Grid Overlap + Bar
    grid_chart = charts.Grid(
        init_opts=opts.InitOpts(
            width="100%",
            height="600px",
            animation_opts=opts.AnimationOpts(animation=False),
        )
    )
    grid_chart.add(
        overlap_kline_line,
        grid_opts=opts.GridOpts(pos_left="10%", pos_right="8%", height="50%"),
    )
    grid_chart.add(
        bar,
        grid_opts=opts.GridOpts(
            pos_left="10%", pos_right="8%", pos_top="63%", height="16%"
        ),
    )

    return grid_chart




def build_realtime_chart(bars:List[BarData],order_list = None):
    """
    构建分钟实时图
    :order_list:
        委托单:
        time

    """
    pre_close = bars[0].pre_close

    ### 构建前30分钟的bar
    prepare_bars = []
    for i in range(0,30):
        _bar: BarData = BarData.copy(bars[0])
        _bar.datetime = _bar.datetime.replace(hour=9, minute=0, second=0)
        _bar.high = pre_close
        _bar.close = pre_close
        _bar.high = pre_close
        _bar.low = pre_close
        _bar.volume = 0
        _bar.amount = 0
        prepare_bars.append(_bar)

    prepare_bars.extend(bars)
    data_map = _utils.make_k_bars_data(prepare_bars, is_daily_time=False)
    time_list = data_map['time']
    time_value = data_map['time_value']
    candle_values = data_map['k_bar']

    close_values_list = [kbar[1] for kbar in candle_values]
    mark_lines = []
    min_ = data_map["min_value"]
    max_ = data_map["max_value"]
    min_ = min(min_, pre_close)
    max_ = max(max_, pre_close)
    mark_lines.append(opts.MarkLineItem(name=f"0%", y=pre_close, symbol="none"))
    tool_tip_fun = JsCode("""
                        function(params) {
                            return '' + params.data[1];
                        }
                    """)
    mark_point_js = JsCode("""
                                function(params) {
                                    return params.name +':' + params.value;
                                }
                            """)

    mark_point_list = []

    ### 增加委托单标识
    if order_list:
        for order in order_list:
            order = order
            if not utils.is_same_day(order.time,time_value[0]):
                continue
            min_ = min(min_, order.price)
            max_ = max(max_, order.price)

            percent_des = f"{100 * (order.price - pre_close) / pre_close:.1f}%"

            if order.direction.__contains__("卖出"):
                _mark_name = f"卖出({percent_des})"
                if order.is_finished():
                    _mark_name = f"已卖({percent_des})"
                _symbol ='diamond'
                _color = 'green'
            else:
                _mark_name = f"买入({percent_des})"
                _symbol ='triangle'
                _color = 'red'
                if order.is_finished():
                    _mark_name = f"已买({percent_des})"


            _index = len(time_list) - 1

            if order.is_finished():
                ### 找到最近的时间点。
                _the_near_time = 0
                _color = 'grey'
                for _i in range(len(time_value)):
                    if order.time < time_value[_i]:
                        break
                    _the_near_time = _i
                if _the_near_time != -1:
                    _index = _the_near_time
            mark_point_list.append(opts.MarkPointItem(
                name=_mark_name,
                coord=[time_list[_index],order.price],
                value = order.price,# 标注值，可以不设。
                symbol_size= "15",
                symbol=_symbol, # 'circle', 'rect', 'roundRect', 'triangle',  'diamond', 'pin', 'arrow', 'none'
                itemstyle_opts = opts.ItemStyleOpts(color=_color)
            ))


    min_ = int(min_ * 0.99 * 100) / 100
    max_ = int(max_ * 1.01 * 100 ) / 100

    kline = (
        charts.Line()
            .add_xaxis(xaxis_data=time_list)
            .add_yaxis(
                series_name="chart",
                y_axis=close_values_list,
                label_opts=opts.LabelOpts(is_show=False),
                itemstyle_opts = opts.ItemStyleOpts(color='black'),
                markline_opts=opts.MarkLineOpts(
                    data=mark_lines,
                    is_silent=False,
                    label_opts=opts.LabelOpts(is_show=True)
                ),
                markpoint_opts=opts.MarkPointOpts(
                    data=mark_point_list,
                    label_opts=opts.LabelOpts(
                        is_show=True,
                        formatter=mark_point_js
                    ))
            ##itemstyle_opts=opts.ItemStyleOpts(color="#ec0000", color0="#00da3c"),
            )
            .set_global_opts(
                legend_opts=opts.LegendOpts(
                    is_show=False, pos_bottom=10, pos_left="center"
                ),
                yaxis_opts=opts.AxisOpts(
                    is_scale=True,
                    # splitarea_opts=opts.SplitAreaOpts(
                    #     is_show=True, areastyle_opts=opts.AreaStyleOpts(opacity=1)
                    # ),
                    min_=min_,
                    max_=max_,
                ),
                tooltip_opts=opts.TooltipOpts(
                    trigger="item",
                    axis_pointer_type="cross",
                    background_color="rgba(245, 245, 245, 0.8)",
                    border_width=1,
                    #formatter="hha:{c1}",
                    formatter = tool_tip_fun,
                    border_color="#ccc",
                    textstyle_opts=opts.TextStyleOpts(color="#000"),
                ),
            )
    )

    return kline